package com.aoyang.modbus.entity;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Record:
 *
 * @author Jcx
 * @create 2023-04-03 21:49
 */
public class Record extends LinkedHashMap<String, Object> implements Serializable {

    /**
     * 用作 String 时的默认 KEY
     */
    public static final String RECORD_KEY = "key";

    private static final long serialVersionUID = 1L;

    public Record() {
    }

    /**
     * 根据 Key 获取值
     *
     * @param key 键
     * @return 值
     */
    @Override
    public Object get(Object key) {
        if ("this".equals(key)) {
            return this;
        }
        return super.get(key);
    }

    /**
     * 根据 Key 获取值
     * <p>
     * 如果为空，则返回默认值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    public Object get(Object key, Object defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 根据 Key 获取字符串值
     *
     * @param key 键
     * @return 值
     */
    public String getStr(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return null;
        }
        return String.valueOf(value);
    }


    /**
     * 根据 Key 获取字符串值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    public String getStr(String key, String defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return String.valueOf(value);
    }

    /**
     * 根据 Key 获取整形值
     *
     * @param key 键
     * @return 值
     */
    public int getInt(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return 0;
        }
        return Integer.parseInt(String.valueOf(value));
    }

    /**
     * 根据 Key 获取整形值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    public int getInt(String key, int defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return Integer.parseInt(String.valueOf(value));
    }

    /**
     * 根据 Key 获取长整形值
     *
     * @param key 键
     * @return 值
     */
    public long getLong(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return 0;
        }
        return Long.parseLong(String.valueOf(value));
    }

    /**
     * 根据 Key 获取长整形值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    public long getLong(String key, long defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return Long.parseLong(String.valueOf(value));
    }

    /**
     * 根据 Key 获取浮点型值
     *
     * @param key 键
     * @return 值
     */
    public double getDouble(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return 0.0;
        }
        return Double.parseDouble(String.valueOf(value));
    }

    /**
     * 根据 Key 获取浮点型值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    public double getDouble(String key, double defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return Double.parseDouble(String.valueOf(value));
    }

    /**
     * 根据 Key 获取布尔型值
     *
     * @param key 键
     * @return 值
     */
    public boolean getBoolean(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return false;
        }
        return Boolean.parseBoolean(String.valueOf(value));
    }

    /**
     * 根据 Key 获取布尔型值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    public boolean getBoolean(String key, boolean defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return Boolean.parseBoolean(String.valueOf(value));
    }

    /**
     * 根据 Key 获取 format 格式化后的 Date
     *
     * @param key    键
     * @param format 格式化字符串
     * @return 格式化后的时间对象
     */
    public Date getDateByFormat(String key, String format) {
        try {
            return new SimpleDateFormat(format).parse(getStr(key));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据 Key 获取格式为 yyyy-MM-dd 的 Date
     *
     * @param key 键
     * @return 格式为 yyyy-MM-dd 的 Date
     */
    public Date getDate(String key) {
        return getDateByFormat(key, "yyyy-MM-dd");
    }

    /**
     * 根据 Key 获取格式为 yyyy-MM-dd HH:mm:ss 的 Date
     *
     * @param key 键
     * @return 格式为 yyyy-MM-dd HH:mm:ss 的 Date
     */
    public Date getDateTime(String key) {
        return getDateByFormat(key, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 获取集合
     * <p>
     * 必须原先就是个集合，否则会创建个新集合并返回
     *
     * @param key 键
     * @return 集合
     */
    public List<Object> getList(String key) {
        Object value = get(key);
        List<Object> list = null;
        if (ObjectUtil.isEmpty(value)) {
            list = new ArrayList<Object>();
        } else if (value instanceof List) {
            list = (List<Object>) value;
        } else {
            list = new ArrayList<Object>();
            list.add(value);
        }
        return list;
    }

    /**
     * 获取指定泛型类型的集合
     *
     * @param key 键
     * @param cs  泛型类型
     * @param <T> 泛型
     * @return 指定泛型类型的集合
     */
    public <T> List<T> getList(String key, Class<T> cs) {
        List<Object> list = getList(key);
        List<T> list2 = new ArrayList<T>();
        for (Object obj : list) {
            T objC = getValueByClass(obj, cs);
            list2.add(objC);
        }
        return list2;
    }

    /**
     * 获取指定泛型类型的集合
     * <p>
     * 将获取到的值按照 逗号 分割保存为一个集合
     *
     * @param key 键
     * @param cs  泛型类型
     * @param <T> 泛型
     * @return 指定泛型类型的集合
     */
    public <T> List<T> getListByComma(String key, Class<T> cs) {
        String listStr = getStr(key);
        if (StrUtil.isEmpty(listStr)) {
            return new ArrayList<>();
        }
        // 开始转化
        String[] arr = listStr.split(",");
        List<T> list = new ArrayList<T>();
        for (String str : arr) {
            if (cs == int.class || cs == Integer.class || cs == long.class || cs == Long.class) {
                str = str.trim();
            }
            T objC = getValueByClass(str, cs);
            list.add(objC);
        }
        return list;
    }

    /**
     * 将本 map 转为指定类型对象
     *
     * @param cs  泛型类型
     * @param <T> 泛型
     * @return 指定类型对象
     */
    public <T> T getModel(Class<T> cs) {
        try {
            return getModelByObject(cs.newInstance());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据指定类型从 map 中取值，返回实体对象
     *
     * @param key 键
     * @param cs  泛型类型
     * @param <T> 泛型
     * @return 指定类型对象
     */
    public <T> T getModel(String key, Class<T> cs) {
        try {
            return getValueByClass(this.get(key), cs);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 传入一个对象将 map 中与对象属性名一致的值填入对象属性值
     *
     * @param obj 对象实列
     * @param <T> 泛型
     * @return 填充数据后的对象实列
     */
    public <T> T getModelByObject(T obj) {
        // 获取类型
        Class<?> cs = obj.getClass();
        // 循环复制
        for (Field field : cs.getDeclaredFields()) {
            try {
                // 获取对象
                Object value = this.get(field.getName());
                if (ObjectUtil.isEmpty(value)) {
                    continue;
                }
                field.setAccessible(true);
                Object valueConvert = getValueByClass(value, field.getType());
                field.set(obj, valueConvert);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new RuntimeException("属性取值出错：" + field.getName(), e);
            }
        }
        return obj;
    }

    /**
     * 将指定值转化为指定类型并返回
     *
     * @param obj 对象
     * @param cs  类型
     * @param <T> 泛型
     * @return 指定类型的对象
     */
    public static <T> T getValueByClass(Object obj, Class<T> cs) {
        String obj2 = String.valueOf(obj);
        Object obj3 = null;
        if (cs.equals(String.class)) {
            obj3 = obj2;
        } else if (cs.equals(int.class) || cs.equals(Integer.class)) {
            obj3 = Integer.valueOf(obj2);
        } else if (cs.equals(long.class) || cs.equals(Long.class)) {
            obj3 = Long.valueOf(obj2);
        } else if (cs.equals(short.class) || cs.equals(Short.class)) {
            obj3 = Short.valueOf(obj2);
        } else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
            obj3 = Byte.valueOf(obj2);
        } else if (cs.equals(float.class) || cs.equals(Float.class)) {
            obj3 = Float.valueOf(obj2);
        } else if (cs.equals(double.class) || cs.equals(Double.class)) {
            obj3 = Double.valueOf(obj2);
        } else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
            obj3 = Boolean.valueOf(obj2);
        } else {
            obj3 = (T) obj;
        }
        return (T) obj3;
    }

    /**
     * 给指定 键 设置 值
     *
     * @param key   键
     * @param value 值
     * @return 设置完后的集合
     */
    public Record set(String key, Object value) {
        // 防止敏感key
        if ("this".equals(key.toLowerCase())) {
            return this;
        }
        put(key, value);
        return this;
    }

    /**
     * 给指定 键 设置 值
     *
     * @param key          键
     * @param defaultValue 值
     */
    public void setDefaultValue(String key, Object defaultValue) {
        if (StrUtil.isNotEmpty(key)) {
            set(key, defaultValue);
        }
    }

    /**
     * 将一个 Map 设置到 Record 中
     *
     * @param map map
     * @return Record
     */
    public Record setMap(Map<String, ?> map) {
        if (ObjectUtil.isNotEmpty(map)) {
            for (String key : map.keySet()) {
                this.set(key, map.get(key));
            }
        }
        return this;
    }

    /**
     * 将一个对象解析塞进 Record
     *
     * @param model 对象实列
     * @return Record
     */
    public Record setModel(Object model) {
        if (ObjectUtil.isEmpty(model)) {
            return Record.getRecord();
        }
        if (model instanceof Record) {
            return (Record) model;
        }
        if (model instanceof String) {
            this.set(RECORD_KEY, model);
        } else {
            List<Field> fieldList = reflectForField(model.getClass());
            if (ObjectUtil.isNotEmpty(fieldList)) {
                for (Field field : fieldList) {
                    try {
                        field.setAccessible(true);
                        boolean isStatic = Modifier.isStatic(field.getModifiers());
                        if (!isStatic) {
                            this.set(field.getName(), field.get(model));
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return this;
    }

    /**
     * 将类的所有属性拆解为一个属性集合
     *
     * @param clazz 类对象
     * @param <T>   泛型
     * @return 属性集合
     */
    private <T> List<Field> reflectForField(Class<T> clazz) {
        Class tmpClazz = clazz;
        List<Field> fieldList = new ArrayList<>();
        while (tmpClazz != null) {
            if (tmpClazz.equals(Object.class)) {
                tmpClazz = tmpClazz.getSuperclass();
                continue;
            }
            fieldList.addAll(new ArrayList<>(Arrays.asList(tmpClazz.getDeclaredFields())));
            tmpClazz = tmpClazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fieldList;
    }

    /**
     * 根据 键 删除值
     *
     * @param key 键
     * @return 删除后的对象
     */
    public Record delete(String key) {
        remove(key);
        return this;
    }

    /**
     * 清理所有 value 为 null 的字段
     *
     * @return 删除后的对象
     */
    public Record clearNull() {
        Iterator<String> iterator = this.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (StrUtil.isEmpty(key)) {
                iterator.remove();
                this.remove(key);
            }
        }
        return this;
    }

    /**
     * 清理指定 key
     *
     * @param keys 指定的 key
     * @return 删除后的对象
     */
    public Record clearIn(String... keys) {
        List<String> keys2 = Arrays.asList(keys);
        Iterator<String> iterator = this.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (keys2.contains(key)) {
                iterator.remove();
                this.remove(key);
            }
        }
        return this;
    }

    /**
     * 清理掉不在列表中的 key
     *
     * @param keys 指定的 key
     * @return 删除后的对象
     */
    public Record clearNotIn(String... keys) {
        List<String> keys2 = Arrays.asList(keys);
        Iterator<String> iterator = this.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (!keys2.contains(key)) {
                iterator.remove();
                this.remove(key);
            }
        }
        return this;
    }

    /**
     * 清空
     *
     * @return 清空后的对象
     */
    public Record clearAll() {
        clear();
        return this;
    }

    /**
     * @return 构建一个 Record 并返回
     */
    public static Record getRecord() {
        return new Record();
    }

    /**
     * 构建一个初始化数据的 Record 并返回
     *
     * @param key   键
     * @param value 值
     * @return 带初始化数据的 Record
     */
    public static Record getRecord(String key, Object value) {
        return new Record().set(key, value);
    }

    /**
     * 构建一个初始化数据的 Record 并返回
     *
     * @param map 键值对
     * @return 初始化数据的 Record
     */
    public static Record getRecord(Map<String, ?> map) {
        return new Record().setMap(map);
    }

    /**
     * 将对象解析后塞到 Record 中并返回
     *
     * @param model 对象
     * @return 对象 Record
     */
    public static Record getRecordByModel(Object model) {
        return Record.getRecord().setModel(model);
    }

    /**
     * 将一个对象集合解析成为 Record 集合
     *
     * @param list 集合
     * @return Record 集合
     */
    public static List<Record> getRecordByList(List<?> list) {
        List<Record> listMap = new ArrayList<>();
        for (Object model : list) {
            if (model instanceof Record) {
                listMap.add((Record) model);
            } else {
                listMap.add(getRecordByModel(model));
            }
        }
        return listMap;
    }

    /**
     * 克隆指定 key，返回一个新的 Record
     *
     * @param keys 要克隆的 key
     * @return 新的 Record
     */
    public Record cloneKeys(String... keys) {
        Record record = new Record();
        for (String key : keys) {
            record.set(key, this.get(key));
        }
        return record;
    }

    /**
     * 克隆所有 key，返回一个新的 Record
     *
     * @return 新的 Record
     */
    public Record cloneRecord() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(key, this.get(key));
        }
        return record;
    }

    /**
     * 将所有 key 转为大写
     *
     * @return 转换后的 Record
     */
    public Record toUpperCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(key.toUpperCase(), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 将所有 key 转为小写
     *
     * @return 转换后的 Record
     */
    public Record toLowerCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(key.toLowerCase(), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 将所有 key 中下划线转为中划线模式 ( kebab-case 风格)
     *
     * @return 转换后的 Record
     */
    public Record toKebabCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(wordEachKebabCase(key), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 下划线转中划线
     *
     * @param str 传入字符串
     * @return 转换后的字符串
     */
    public static String wordEachKebabCase(String str) {
        return str.replaceAll("_", "-");
    }

    /**
     * 将所有 key 中下划线转为小驼峰模式
     *
     * @return 转换后的 Record
     */
    public Record toHumpCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(wordEachBigFs(key), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 返回下划线转小驼峰形式
     *
     * @param str 传入字符串
     * @return 转换后的字符串
     */
    public static String wordEachBigFs(String str) {
        return wordFirstSmall(wordEachBig(str));
    }

    /**
     * 将指定单词首字母小写
     *
     * @param str 传入字符串
     * @return 转换后的字符串
     */
    public static String wordFirstSmall(String str) {
        return str.substring(0, 1).toLowerCase() + str.substring(1);
    }

    /**
     * 指定字符串的字符串下划线转大写模式
     *
     * @param str 传入字符串
     * @return 转换后的字符串
     */
    public static String wordEachBig(String str) {
        StringBuilder newStr = new StringBuilder();
        for (String s : str.split("_")) {
            newStr.append(wordFirstBig(s));
        }
        return newStr.toString();
    }

    /**
     * 将指定单词首字母大写
     *
     * @param str 传入字符串
     * @return 转换后的字符串
     */
    public static String wordFirstBig(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * 将所有 key 中小驼峰转为下划线模式
     *
     * @return 转换后的 Record
     */
    public Record humpToLineCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(wordHumpToLine(key), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 驼峰转下划线
     *
     * @param str 传入字符串
     * @return 转换后的字符串
     */
    public static String wordHumpToLine(String str) {
        return str.replaceAll("[A-Z]", "_$0").toLowerCase();
    }

    /**
     * 指定 key 的 value 是否为数字
     *
     * @param key 键
     * @return 是否
     */
    public boolean isNumber(String key) {
        String value = getStr(key);
        if (StrUtil.isEmpty(value)) {
            return false;
        }
        return Pattern.compile("[0-9]*").matcher(value).matches();
    }

    public static List<Record> pruneTree(List<Record> treeList, String childListKey, String key, String value) {
        List<Record> prunedList = new ArrayList<>();
        for (Record node : treeList) {
            if (node.getStr(key).equals(value)) {
                // 当前节点符合条件，
                continue;
            }
            // 更新当前节点的子集合为裁剪后的子集合
            node.put(childListKey, pruneTree(node.getList(childListKey, Record.class), childListKey, key, value));
            prunedList.add(node);
        }
        return prunedList;
    }

    public static List<Record> findTreeNodePath(List<Record> treeList, String childListKey, String key, String value) {
        List<Record> nodePath = new ArrayList<>();
        findTreeNodePathRecursive(treeList, childListKey, key, value, nodePath);
        // 将链路反转，使根节点在第一个位置
        Collections.reverse(nodePath);
        return nodePath;
    }

    private static boolean findTreeNodePathRecursive(List<Record> nodes, String childListKey, String key, String value, List<Record> nodePath) {
        for (Record node : nodes) {
            // 当前节点符合条件
            if (node.getStr(key).equals(value)) {
                // 找到目标节点，将其加入链路并返回 true
                nodePath.add(node);
                return true;
            } else {
                // 继续递归查找子节点
                if (findTreeNodePathRecursive(node.getList(childListKey, Record.class), childListKey, key, value, nodePath)) {
                    // 如果找到目标节点，则将当前节点加入链路并返回 true
                    nodePath.add(node);
                    return true;
                }
            }
        }
        // 当前节点及其子节点中没有目标节点
        return false;
    }

    /**
     * 将 list 转为 树形
     *
     * @param list         集合对象
     * @param idKey        主键名
     * @param parentIdKey  父主键名
     * @param childListKey 子集键名
     * @return 树形集合
     */
    public static List<Record> listToTree(List<Record> list, String idKey, String parentIdKey, String childListKey) {
        // 声明新的集合，存储tree形数据
        List<Record> newTreeList = new ArrayList<Record>();
        // 声明hash-Map，方便查找数据
        Record hash = new Record();
        // 将数组转为Object的形式，key为数组中的id
        for (int i = 0; i < list.size(); i++) {
            Record json = (Record) list.get(i);
            hash.put(json.getStr(idKey), json);
        }
        // 遍历结果集
        for (int j = 0; j < list.size(); j++) {
            // 单条记录
            Record aVal = (Record) list.get(j);
            // 在hash中取出key为单条记录中pid的值
            Record hashVp = (Record) hash.get(aVal.get(parentIdKey, "").toString());
            // 如果记录的pid存在，则说明它有父节点，将她添加到孩子节点的集合中
            if (hashVp != null) {
                // 检查是否有child属性，有则添加，没有则新建
                if (hashVp.get(childListKey) != null) {
                    @SuppressWarnings("unchecked") List<Record> ch = (List<Record>) hashVp.get(childListKey);
                    ch.add(aVal);
                    hashVp.put(childListKey, ch);
                } else {
                    List<Record> ch = new ArrayList<Record>();
                    ch.add(aVal);
                    hashVp.put(childListKey, ch);
                }
            } else {
                newTreeList.add(aVal);
            }
        }
        return newTreeList;
    }

}
